# -*- coding: utf-8 -*-
# @Time    : 2021/9/18 15:24
# @Author  : BrandonGT
# @FileName: maya_analyser.py

# Python 标准库
import os
import time
import re
import logging

# 第三方+ 自定义库
from blogger import BLogger


class MayaFileAnalyser(object):
    """Maya文件信息分析
    Methods介绍：
        process_bar: 进度条显示
        set_file: 指定需要分析的文件，需要传入文件的绝对路径
        get_file_name: 获取文件名
        get_time: 获取文件的 创建时间、修改时间和最后打开的时间
        get_size: 获取文件大小
        read_file: 读取maya MA文件信息
        decode_file: 分析MA文件获取值
        analyse: 读取 + 分析
        create_log: 生成日志文件
    """

    def __init__(self, fpath=""):
        """定义各类用于查询的信息属性"""
        self.abs_path = fpath  # 文件绝对路径
        self.root_path = ""  # 文件的根目录路径
        self.file_name = ""  # 文件名
        self.date_create = ""  # 创建日期
        self.date_modify = ""  # 最后修改日期
        self.date_last_open = ""  # 最新访问日期
        self.file_size = ""  # 文件大小
        self.maya_version = ""  # 文件制作的maya版本
        self.frame_start = 0  # 起始帧
        self.frame_end = 0  # 结束帧
        self.cameras = []  # 相机
        self.active_cameras = []  # 有效相机
        self.props = []  # 非ref资产
        self.ref_props = []  # ref资产
        self.expressions = []  # 表达式
        self.requires = {}  # Plugins需求
        self.file_context = []  # 存储MA信息
        self.file_len = 0  # MA文件的行数

    # def process_bar(self, percent, start="", end="", total=0):
    #     """简易进度条"""
    #     bar = ''.join(["\033[31m%s\033[0m" % '   '] * int(percent * total)) + ''
    #     bar = '\r' + start + bar.ljust(total) + ' {:0>4.1f}%|'.format(percent * 100) + end
    #     print(bar, end='', flush=True)

    def set_file(self, fpath):
        """设置文件路径, 检查是否为路径， 验证文件是否存在，且是否为MA格式"""
        is_str = 1 if isinstance(fpath, str) else 0  # 验证输入的是否为str类型的路径
        is_exist = 1 if os.path.isfile(fpath) else 0  # 验证文件是否存在
        is_ma = 0
        if is_str and is_exist:
            file_ext = fpath.split(".")[-1]
            is_ma = 1 if file_ext == 'ma' else 0

        if is_ma:
            self.abs_path = fpath  # 当所有验证通过时，将abs_path设置为当前输入的路径

        # 返回错误信息
        if not is_str:
            raise ValueError("Input has to be str type, receive: {0}".format(fpath))
        if not is_exist:
            raise FileNotFoundError("Input must be a file path, receive: {0}".format(fpath))
        if not is_ma:
            raise ValueError("Input is not a MA file, receive: {0}".format(fpath))

    def get_root_path(self):
        """获取文件所在的根目录路径"""
        self.root_path = self.abs_path.replace("\\", "/")[::-1].split("/", 1)[-1][::-1]

        return self.root_path

    def get_file_name(self, ext=1):
        """获取并返回 文件名, 可选是否带拓展名, 默认带扩展名"""
        name_with_ext = self.abs_path.replace("\\", "/").split("/")[-1]
        if ext:
            self.file_name = name_with_ext
        else:
            self.file_name = name_with_ext.split(".")[0]

        return self.file_name

    def get_time(self):
        """获取并选择性返回 文件的创建时间、最后修改时间、最新访问日期"""
        time_format = "%Y-%m-%d %H:%M:%S"
        file_object = os.stat(self.abs_path) if self.abs_path else 0
        if file_object:
            self.date_modify = time.strftime(time_format, time.localtime(file_object.st_mtime))
            self.date_create = time.strftime(time_format, time.localtime(file_object.st_ctime))
            self.date_last_open = time.strftime(time_format, time.localtime(file_object.st_atime))
        else:
            raise FileNotFoundError("Please set validate file path first")

        times = {
            "modify": self.date_modify,
            "create": self.date_create,
            "last_open": self.date_last_open,
        }

        return times

    def get_size(self):
        """获取并返回文件大小"""
        file_object = os.stat(self.abs_path) if self.abs_path else 0
        if file_object:
            self.file_size = round(file_object.st_size / 1024)  # 返回KB
        else:
            raise FileNotFoundError("Please set validate file path first")

        return self.file_size

    def read_file(self):
        """读取MA信息存于列表，一行一个元素"""
        with open(self.abs_path, 'r') as f:
            for line in f:
                self.file_context.append(line.rstrip())
        # self.file_len = len(self.file_context)

    def decode_file(self):
        """用于分析MA文件，并将搜索到的内容保存至字典"""

        # 定义re匹配的词缀
        re_version = re.compile('(?<=\/\/Maya ASCII ).*?(?= scene)')
        re_frames = re.compile('(?<="playbackOptions -min )(\d+)(?= ) -max (\d+)(?= \-ast)')
        re_active_camera = re.compile('(?<=createNode camera -n )[\S].*?(?<= \-p ")([\w].*?)(?=")')
        re_props = re.compile('(?<=createNode transform -n ")([\w]\S*[^\d+\-\d+])(?=";)')
        re_refs = re.compile('(?<=file -rdi 1 -ns ")([\w]\S*)(?=" -rfn)')
        re_script = re.compile('(?<=createNode script -n ")(\S*?:vaccine_gene\
        \d*?|\S*?:breed_gene\d*?|vaccine_gene\d*?|breed_gene\d*?)(?=";)')
        re_require_a = re.compile('(?<=requires )[\w\-"].*["](.*)["] ["](.*)["](?=;)')
        re_require_b = re.compile('(?<=requires)[\w\-"]? ["](.*)["] ["](.*)["](?=;)')

        # # 进行匹配_v01
        # count = 0
        # for content in self.file_context:
        #     end_str = "100%"
        #     self.process_bar(count / self.file_len, end=end_str, total=15)
        #     count += 1
        #     if re_version.search(content):  # 匹配MAYA版本
        #         self.maya_version = str(re_version.search(content).group())
        #
        #     elif re_frames.search(content):  # 匹配帧数信息
        #         content = re_frames.findall(content)
        #         self.frame_start = content[0][0]
        #         self.frame_end = content[0][1]
        #
        #     elif re_active_camera.search(content):  # 匹配所有的相机
        #         self.active_cameras = re_active_camera.findall(content)
        #
        #     elif re_props.search(content):  # 匹配所有非引用资产的根组
        #         self.props.append(re_props.findall(content)[0])
        #
        #     elif re_refs.search(content):  # 匹配所有reference资产的根组
        #         self.ref_props.append(re_refs.findall(content)[0])
        #
        #     elif re_script.search(content):  # 匹配所有的“贼健康”表达式
        #         self.expressions.append(re_script.findall(content)[0])
        #
        #     elif re_require_a.search(content):  # 匹配所有的加载require标准格式
        #         content = re_require_a.findall(content)
        #         self.requires[content[0][0]] = content[0][1]
        #
        #     elif re_require_b.search(content):  # 匹配所有的加载require特殊格式
        #         content = re_require_b.findall(content)
        #         self.requires[content[0][0]] = content[0][1]

        # 进行匹配_v02
        with open(self.abs_path, 'r') as f:
            for line in f:
                content = line.strip()

                if re_version.search(content):  # 匹配MAYA版本
                    self.maya_version = str(re_version.search(content).group())
                    continue

                if re_frames.search(content):  # 匹配帧数信息
                    content = re_frames.findall(content)
                    self.frame_start = content[0][0]
                    self.frame_end = content[0][1]
                    continue

                if re_active_camera.search(content):  # 匹配所有的相机
                    self.active_cameras = re_active_camera.findall(content)
                    continue

                if re_props.search(content):  # 匹配所有非引用资产的根组
                    self.props.append(re_props.findall(content)[0])
                    continue

                if re_refs.search(content):  # 匹配所有reference资产的根组
                    self.ref_props.append(re_refs.findall(content)[0])
                    continue

                if re_script.search(content):  # 匹配所有的“贼健康”表达式
                    self.expressions.append(re_script.findall(content)[0])
                    continue

                if re_require_a.search(content):  # 匹配所有的加载require标准格式
                    content = re_require_a.findall(content)
                    self.requires[content[0][0]] = content[0][1]
                    continue

                if re_require_b.search(content):  # 匹配所有的加载require特殊格式
                    content = re_require_b.findall(content)
                    self.requires[content[0][0]] = content[0][1]
                    continue

    def analyse(self):
        """对文件进行分析，并decode，将获取的内容复制给class的属性"""
        self.get_root_path()
        self.get_file_name()
        self.get_time()
        self.get_size()
        self.decode_file()

    def create_log(self, fpath, del_exist=False, all_in_one=False):
        """将分析的内容输出至指定目录"""
        self.get_file_name()
        # ------------------ 定义log ------------------ 开始
        _LOGGER = ""  # 可以替换成自定义的名字
        _LOGGER_LEVEL = logging.DEBUG  # 调整最低的log console显示级别
        _IS_FILE = True  # 是否生成本地日志文件
        _FILE_LEVEL = logging.INFO  # 调整最低的log文件记录级别
        _IS_CONSOLE = True  # 是否在控制台打印

        # 是否合并输出日志
        if all_in_one:
            _PATH = os.path.join(fpath, "MA文件分析日志.log")
        else:
            _PATH = os.path.join(fpath, f"{self.file_name}.log")  # 根据需求修改本地log文件的命名

        # 刷新日志文件，去掉以前的记录
        if del_exist:
            # _PATH = _PATH.replace("\\\\", "/")
            if os.path.isfile(_PATH):
                os.remove(_PATH)

        logger = BLogger(_LOGGER, level=_LOGGER_LEVEL, file=_IS_FILE, file_level=_FILE_LEVEL, console=_IS_CONSOLE, path=_PATH)
        # ------------------ 定义log ------------------ 结束

        # 进行文件内容分析
        time.sleep(0.2)
        logger.info("Start!!!!!!!!!!!!!!!!!!!!!!!!!")
        self.get_time()
        self.get_size()
        self.analyse()
        logger.info("Analyse Finished")

        # 逐一输出信息
        analyse_info = f"""\t以下是文件分析结果：
        \n{'-'*20} 文件名:{self.get_file_name()} {'-'*20}
        
{'-'*30} 文件基础信息 {'-'*30} 
文件路径：{self.abs_path}
文件创建日期：{self.date_create}
最后修改日期：{self.date_modify}
最近访问日期：{self.date_last_open}
文件数据大小：{self.file_size} KB

{'-'*30} MAYA文件信息 {'-'*30} 
MAYA 文件版本：{self.maya_version}
Plugin需求：{self.requires}

{'-'*30} 文件详细信息 {'-'*30} 
起始帧：{self.frame_start}
结束帧：{self.frame_end}
渲染相机：{self.active_cameras}

{'-'*30} 贼健康表达式 {'-'*30} 
表达式：{self.expressions}

{'-'*30} 以下是非引用资产列表 {'-'*30}"""

        logger.info(analyse_info)
        for prop in self.props:
            logger.info(f"""资产组名：{prop}""")

        logger.info(f"""\n\n{'-'*30} 以下是引用资产列表 {'-'*30}""")

        for ref_prop in self.ref_props:
            if ref_prop:
                logger.info(f"资产组名：{ref_prop}")

        logger.info(f"""\n
{'-'*30} 文件分析已完成 {'-'*30} 
{'-'*120} 
{'-'*120} 
{'-'*120} 
\n\n\n 
        """)


if __name__ == '__main__':
    path = r"D:\BaiduNetdiskDownload\maya_analysis\aa.ma"
    # path4 = r"D:\BaiduNetdiskDownload\maya_analysis\aa2.ma"
    # path3 = r"D:\BaiduNetdiskDownload\maya_analysis\PVKXA_sc01_c007_ani.ma"
    # path2 = r"D:\BaiduNetdiskDownload\maya_analysis\PVKXA_Baijin_mod_h.ma"
    # path1 = r"D:\bebe_work\Bebe_Render_v05.ma"
    #
    # paths = [path4, path3, path2, path1]

    # analyser = MayaFileAnalyser(path)
    # analyser.create_log(analyser.get_root_path(), all_in_one=True)
    # # analyser.analyse()
    # print(analyser.active_cameras)
    # print(analyser.ref_props)
    # print(analyser.frame_start)
    # print(analyser.date_last_open)
    # print(analyser.date_modify)
    # print(analyser.file_name)

    # for path in paths:
    #     analyser = MayaFileAnalyser(path)
    #     thred = threading.Thread(target=analyser.create_log, args=(analyser.get_root_path(),))
    #     thred.start()
    pass
